using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;


namespace Mpi.Common
{
    public static class TimeSpanExtension
    {
        public static TimeSpan Parse(string timeSpanStr)
        {
            return TimeSpanExtension.Parse(timeSpanStr, TimeSpanParseOption.DoubleIsDay);
        }

        public static TimeSpan Parse(string timeSpanStr, TimeSpanParseOption opt)
        {
            string s = timeSpanStr.Trim();

            TimeSpan ret = default(TimeSpan);
            TimeSpanSyntax tss = TimeSpanExtension.Evaluate(s, opt);
            switch (tss)
            {
                case TimeSpanSyntax.DayToSecond:
                    {
                        ret = TimeSpan.Parse(s);
                        break;
                    }
                case TimeSpanSyntax.DayToMinute:
                    {
                        ret = TimeSpan.Parse(s);
                        break;
                    }
                case TimeSpanSyntax.DayToHour:
                    {
                        string[] dh = s.Split('.');
                        ret = TimeSpan.FromDays(Double.Parse(dh[0]));
                        ret += TimeSpan.FromHours(Double.Parse(dh[1]));
                        break;
                    }
                case TimeSpanSyntax.HourToSecond:
                    {
                        ret = TimeSpan.Parse(s);
                        break;
                    }
                case TimeSpanSyntax.HourToMinute:
                    {
                        ret = TimeSpan.Parse(s);
                        break;
                    }
                case TimeSpanSyntax.Hour:
                    {
                        ret = TimeSpan.FromHours(Double.Parse(s));
                        break;
                    }
                case TimeSpanSyntax.Day:
                    {
                        ret = TimeSpan.Parse(s);
                        break;
                    }
                case TimeSpanSyntax.Invalid:
                    {
                        break;
                    }
                default:
                    break;
            }
            return ret;
        }

        public static TimeSpanSyntax Evaluate(string timeSpanStr, TimeSpanParseOption opt)
        {
            string s = timeSpanStr.Trim();

            string DtS = @"([1-9][0-9]*\.){1}(([0-1][0-9]|[2][0-3]){1}(:[0-5][0-9]){2})";
            string DtM = @"([1-9][0-9]*\.){1}(([0-1][0-9]|[2][0-3]){1}(:[0-5][0-9]){1})";
            string DtH = @"([1-9][0-9]*\.){1}([0-1][0-9]|[2][0-3])";
            string HtS = @"([0-1][0-9]|[2][0-3]){1}(:[0-5][0-9]){2}";
            string HtM = @"([0-1][0-9]|[2][0-3]){1}(:[0-5][0-9]){1}";
            string H = @"([2][0-3])|([0-1]{0,1}[0-9])";
            string D = @"([1-9][0-9]*)";


            Regex regex;
            Match m;

            regex = new Regex(DtS);
            m = regex.Match(s);
            if (m.Success && m.Length == s.Length)
            {
                return TimeSpanSyntax.DayToSecond;
            }
            regex = new Regex(DtM);
            m = regex.Match(s);
            if (m.Success && m.Length == s.Length)
            {
                return TimeSpanSyntax.DayToMinute;
            }
            regex = new Regex(DtH);
            m = regex.Match(s);
            if (m.Success && m.Length == s.Length)
            {
                return TimeSpanSyntax.DayToHour;
            }
            regex = new Regex(HtS);
            m = regex.Match(s);
            if (m.Success && m.Length == s.Length)
            {
                return TimeSpanSyntax.HourToSecond;
            }
            regex = new Regex(HtM);
            m = regex.Match(s);
            if (m.Success && m.Length == s.Length)
            {
                return TimeSpanSyntax.HourToMinute;
            }
            if (opt == TimeSpanParseOption.DoubleIsHour)
                regex = new Regex(H);
            else
                regex = new Regex(D);
            m = regex.Match(s);
            if (m.Success && m.Length == s.Length)
            {
                if (opt == TimeSpanParseOption.DoubleIsHour)
                    return TimeSpanSyntax.Hour;
                else
                    return TimeSpanSyntax.Day;

            }

            return TimeSpanSyntax.Invalid;

        }

        public static string ValidPattern(TimeSpanParseOption tsp)
        {
            if (tsp == TimeSpanParseOption.DoubleIsDay)
                return @"(([1-9][0-9]{0,3}\.){0,1}(([0-1][0-9]|[2][0-3]){1}(:[0-5][0-9]){0,2}))|[1-9][0-9]{0,3}";
            else if (tsp == TimeSpanParseOption.DoubleIsHour)
                return @"(([1-9][0-9]{0,3}\.){0,1}(([0-1][0-9]|[2][0-3]){1}(:[0-5][0-9]){0,2}))|([2][0-3])|([0-1]{0,1}[0-9])";
            else return String.Empty;
        }

        public static string OptimizedStringRepresentation(TimeSpan ts, TimeSpanParseOption tspo)
        {
            if (ts == TimeSpan.Zero)
                return "0";


            StringBuilder sb = new StringBuilder();


            TimeSpanSyntax tss = TimeSpanExtension.OptimizeLevel(ts, tspo);
            switch (tss)
            {
                case TimeSpanSyntax.DayToSecond:
                    {
                        sb.Append(ts.ToString());
                        break;
                    }
                case TimeSpanSyntax.DayToMinute:
                    {
                        sb.AppendFormat("{0}.", ts.Days);
                        goto case TimeSpanSyntax.HourToMinute ;
                        //break;
                    }
                case TimeSpanSyntax.DayToHour:
                    {
                        if(ts.Hours < 10)
                            sb.AppendFormat("{0}.0{1}",ts.Days,ts.Hours);
                        else
                            sb.AppendFormat("{0}.{1}", ts.Days, ts.Hours);
                        break;
                    }
                case TimeSpanSyntax.HourToSecond:
                    {
                        sb.Append(ts.ToString());
                        break;
                    }
                case TimeSpanSyntax.HourToMinute:
                    {
                        if (ts.Hours < 10)
                        {
                            if(ts.Minutes < 10)
                                sb.AppendFormat("0{0}:0{1}", ts.Hours, ts.Minutes);
                            else
                                sb.AppendFormat("0{0}:{1}", ts.Hours, ts.Minutes);
                        }
                        else
                        {
                            if (ts.Minutes < 10)
                                sb.AppendFormat("{0}:0{1}", ts.Hours, ts.Minutes);
                            else
                                sb.AppendFormat("{0}:{1}", ts.Hours, ts.Minutes);
                        }
                        
                        break;
                    }
                case TimeSpanSyntax.Hour:
                    {
                        sb.Append(ts.Hours);
                        break;
                    }
                case TimeSpanSyntax.Day:
                    {
                        sb.Append(ts.Days);
                        break;
                    }
                default:
                    {
                        sb.Append(ts.ToString());
                        break;
                    }
            }

            return sb.ToString();
            
        }

        private static TimeSpanSyntax OptimizeLevel(TimeSpan ts, TimeSpanParseOption tspo)
        {
            string start = "H";
            if (ts.Days != 0)
                start = "D";
            string end = "S";
            if (ts.Seconds == 0)
            {
                end = "M";
                if (ts.Minutes == 0)
                {
                    end = "H";
                    if (ts.Hours == 0)
                        end = "D";
                }
            }

            if (start == "D" && end == "S")
                return TimeSpanSyntax.DayToSecond;
            if (start == "D" && end == "M")
                return TimeSpanSyntax.DayToMinute;
            if (start == "D" && end == "H")
                return TimeSpanSyntax.DayToHour;
            if (start == "H" && end == "S")
                return TimeSpanSyntax.HourToSecond;
            if (start == "H" && end == "M")
                return TimeSpanSyntax.HourToMinute;
            if (start == "H" && end == "H")
            {
                if (tspo == TimeSpanParseOption.DoubleIsHour)
                    return TimeSpanSyntax.Hour;
                else
                    return TimeSpanSyntax.HourToMinute;
            }
            if (start == "D" && end == "D")
            {
                if (tspo == TimeSpanParseOption.DoubleIsDay)
                    return TimeSpanSyntax.Day;
                else
                    return TimeSpanSyntax.DayToHour;
            }
            return TimeSpanSyntax.DayToSecond;

        }

        public static string ReadableValueDuration(TimeSpan ts)
        {
           
                ArrayList strings = new ArrayList();

                if (ts.Days % 7 == 0)
                {
                    int weeks = ts.Days / 7;


                    if (weeks == 1)
                    {
                        strings.Add(weeks + " week");
                    }
                    if (weeks > 1)
                    {
                        strings.Add(weeks + " weeks");
                    }
                }
                else
                {
                    if (ts.Days == 1)
                    {
                        strings.Add(ts.Days + " day");
                    }
                    else if (ts.Days > 1)
                    {
                        strings.Add(ts.Days + " days");
                    }
                }
                if (ts.Hours == 1)
                    strings.Add(ts.Hours + " hour");
                if (ts.Hours > 1)
                    strings.Add(ts.Hours + " hours");
                if (ts.Minutes == 1)
                    strings.Add(ts.Minutes + " minute");
                if (ts.Minutes > 1)
                    strings.Add(ts.Minutes + " minutes");
                if (ts.Seconds == 1)
                    strings.Add(ts.Seconds + " second");
                if (ts.Seconds > 1)
                    strings.Add(ts.Seconds + " seconds");
                string r = "";
                for (int i = 0; i < strings.Count; i++)
                {
                    r += strings[i];
                    if (i < strings.Count - 1)
                    {

                        r += ", ";
                    }
                }
                if (r.Length == 0)
                    r = "Zero";
                return r;
        }

        public static string ReadableValuePoint(TimeSpan ts)
        {
            
                ArrayList strings = new ArrayList();

                if (ts.Days > 0)
                {
                    strings.Add("day " + ts.Days);
                }


                if (ts.Hours > 0)
                    strings.Add("hour " + ts.Hours);

                if (ts.Minutes > 0)
                    strings.Add("minute " + ts.Minutes);
                if (ts.Seconds > 0)
                    strings.Add("second " + ts.Seconds);
                string r = "";
                for (int i = 0; i < strings.Count; i++)
                {
                    r += strings[i];
                    if (i < strings.Count - 1)
                    {

                        r += ", ";
                    }
                }
                if (r.Length == 0)
                    r = "Zero";
                return r;
        }
    }


    public enum TimeSpanSyntax
    {
        DayToSecond,
        DayToMinute,
        DayToHour,
        HourToSecond,
        HourToMinute,
        Hour,
        Day,
        Invalid
    }

    public enum TimeSpanParseOption
    {
        DoubleIsDay,
        DoubleIsHour
    }
}
